package service;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class EasyConnection {

	private URL url;
	private HttpURLConnection conn;
	private Map<String, String> params = new HashMap<String, String>();
	private Method method;

	public enum Method {
		GET, POST
	}

    /**
     * @param url valid URL object
     */
	public EasyConnection(URL url){
		this.url = url;
	}

	/**
	 * @param url valid url string
	 * @throws java.io.IOException
	 */
	public EasyConnection(String url) throws IOException{
		this.url = new URL(url);
	}
	
	/**
	 * Open a new connection.
	 * @throws java.io.IOException
	 */
	public void open() throws IOException{
		conn = (HttpURLConnection) this.url.openConnection();
	}
	
	/**
	 * Close the connection.
	 */
	public void close(){
		conn.disconnect();
	}
	
	/**
	 * Recover current properties from the connection. To use this method the connection must be open.
	 * @param key key value to search
	 * @return the value assigned to key
	 */
	public String getProperty(String key){
		return conn.getRequestProperty(key);
	}
	
	/**
	 * @return the actual transfer method
	 */
	public String getMethod(){
		return conn.getRequestMethod();
	}
	
	/**
	 * @param method valid Method enumeration
	 * @throws java.net.ProtocolException
	 */
	public void setMethod(Method method) throws ProtocolException{
		switch(method){
			case GET : 
				conn.setRequestMethod("GET"); 
				break;
			case POST :
				conn.setDoOutput(true);
				conn.setDoInput(true);
				conn.setRequestMethod("POST");
				break;
			default :
				throw new ProtocolException("Invalid Protocol.");
		}
		this.method = method;
	}
	
	/**
	 * @return response code of the last call.
	 * @throws java.io.IOException
	 */
	public int getResponseCode() throws IOException{
		return conn.getResponseCode();
	}

	/**
	 * @param key new key to set
	 * @param value new value to set
	 */
	public void setProperty(String key, String value){
		conn.setRequestProperty(key, value);
	}

	/**
	 * @return the actual property map
	 */
	public Map<String,List<String>> getProperties(){
		return conn.getRequestProperties();
	}
	
	/**
     * Set a new param in the local parameters map.
	 * @param key name
	 * @param value value
	 */
	public void setParameter(String key, String value){
		params.put(key, value);
	}
	
	/**
	 * @param key parameter name
	 * @return the associated value to key
	 */
	public String getParameter(String key){
		return params.get(key);
	}
	
	/**
     * Send all the parameter set with setParameter to a POST call. The connection method must be POST.
	 * @throws java.io.IOException
	 */
	public void sendParameter() throws IOException{
		if (method != Method.POST)
			throw new ProtocolException("Connection method is not POST!");
		StringBuilder sb = new StringBuilder();
		for (String key : params.keySet()) {
			sb.append(key + "=" + params.get(key) + "&");
		}
		sb.setLength(sb.length()-1);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
		bw.write(sb.toString());
		bw.flush();
		bw.close();
	}

	/**
	 * Print to standard out the content received.
	 * @throws java.io.IOException
	 */
	public void printContent() throws IOException{
		if (getResponseCode() != 200)
			throw new IOException("Error: " + getResponseCode());
		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		String str;
		while ((str = br.readLine()) != null)
			System.out.println(str);
	}

    /**
     * @return a new XML Document
     * @throws IOException
     * @throws SAXException
     * @throws ParserConfigurationException
     */
    public Document getXMLContent() throws IOException, SAXException, ParserConfigurationException {
        if (getResponseCode() != 200)
            throw new IOException("Error: " + getResponseCode());

        DocumentBuilderFactory docBuilderFact = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docBuilderFact.newDocumentBuilder();;

        return docBuilder.parse(conn.getInputStream());

    }

    /**
     * @return response content.
     * @throws IOException
     */
    public String getContent() throws IOException{
        if (getResponseCode() != 200)
            throw new IOException("Error: " + getResponseCode());
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuffer sb = new StringBuffer();
        String str;
        while ((str = br.readLine()) != null)
            sb.append(str);
        return sb.toString();
    }

}
